package com.gopay.cashier.web.controller.cloud;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.gopay.common.constants.microdone.EnumMicroScene;
import ocx.AESWithJCE;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.service.riskcontrol.CallRiskControlService;
import com.gopay.cashier.web.command.BankPayWay;
import com.gopay.cashier.web.command.ExpressPayChannelCommand;
import com.gopay.cashier.web.command.ExpressPoundageVo;
import com.gopay.cashier.web.command.OrderInfo;
import com.gopay.cashier.web.utils.BisBankBusinessProdConvertUtil;
import com.gopay.cashier.web.utils.CashierConfig;
import com.gopay.common.Result;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.ExPayBankConstants;
import com.gopay.common.constants.cust.CustCorpInfoConstants;
import com.gopay.common.constants.cust.CustPersonInfoConstants;
import com.gopay.common.constants.cust.UserInfoConstants;
import com.gopay.common.constants.ep.EpCardType;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.GatewaySource;
import com.gopay.common.constants.trans.MerCommPayer;
import com.gopay.common.constants.trans.OrderFeePayer;
import com.gopay.common.constants.trans.PayChannel;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.constants.trans.UserType;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.acps.AcctStatus;
import com.gopay.common.domain.acps.FrezCode;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.PayResult;
import com.gopay.common.domain.cashier.PayDoneResult;
import com.gopay.common.domain.cashier.PayWay;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.ep.EpCardBindInfo;
import com.gopay.common.domain.ep.EpCardStatus;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.domain.user.UserPayPwdResult;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.PwdControlUtil;
import com.gopay.common.util.RequestUtils;
import com.gopay.remote.order.MainOrderField;

/**
 * Created by HJY on 2015/5/11.
 * 网关支付-快捷支付
 * 支付确认 差额支付 国付宝账户支付
 */
@Controller
@RequestMapping("/sec/cloud")
public class CloudExpressPayConfirm00100Controller  extends CloudExpressBaseController {
	
	private static final String CAS_URL = CashierConfig.get(CashierConfig.CAS_SERVER_URL);
    
    @Resource(name="callRiskControlService")
    private CallRiskControlService callRiskControlService;

    @RequestMapping(value = "/00100/express/submit.shtml")
    public ModelAndView submit(ExpressPayChannelCommand exCommand) throws GopayException {
        printRequest("expressPayConfirm00100Controller-submit");

        String mcryptKey = "";
        LoginUser oprInfo = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String status = ProcCodeConstants.PROC_CODE_000S1000;
        String scene = EnumMicroScene.CLOUDAT_EXPRESS_PAY.getCode();
        if(exCommand.getExPayWay() == BankPayWay.A){
            scene = EnumMicroScene.CLOUDAT_BALANCE_PAY.getCode();
        }
        //充值订单
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);

        try {
            if(exCommand.getExPayWay() == BankPayWay.A ||StringUtils.isNotBlank(exCommand.getExCardId())){
                logger.info("需要校验密码，执行获取随机因子");
                mcryptKey = (String) getRequest().getSession().getAttribute("mcrypt_key");
                getRequest().getSession().removeAttribute("mcrypt_key");
                if(StringUtils.isBlank(mcryptKey)){
                    throw new GopayException(ProcCodeConstants.PROC_CODE_100E5120, "浏览器刷新后，请重新输入密码");
                }
                if (StringUtils.isEmpty(exCommand.getPayPassword())){
                    exCommand.setPayPassword(getRequest().getParameter("password"));
                }
            }else {
                logger.info("没有密码输入框，无需校验密码");
            }
            //校验当前登录用户是否通过实名认证  add by fanghw 20151113
            if(exCommand.getExPayWay() != BankPayWay.F){
                checkPayCustRealNameCertify(getLoginUser());
            }


            CpsGenMainOrder order = getMainOrder(orderId, true);
            //系统验证
            validate(exCommand,order);
            //密码验证
            if(!validateSubmit(exCommand,mcryptKey)){
                logger.error("云账户进行密码验证失败，执行nex方法");
                status = exCommand.getErrMsg();
                return next(order,exCommand);
            }

            updateOrder(exCommand,order);

            order = getMainOrder(orderId, true);

            if(exCommand.getExPayWay() != BankPayWay.A){//非余额全额支付
                String inchargeOrderId = saveInchargeOrder(exCommand, order);
                CpsGenMainOrder inchargeOrder = getMainOrder(inchargeOrderId, true);
                updateOrderProcess(inchargeOrder);
                //风控校验
                //rimsProcess(inchargeOrder);

                //调用风控服务校验 add by fanghw 20160122
/*            callRiskControlService.transCall(order.getGopayOrderId(), order.getGopayIntTxnCd(), order.getPayChannel(),
                    order.getMerTxnAmt(), order.getMainRecvCustId());*/

                exCommand.setInChargeOrderId(inchargeOrderId);
                return bankPay(orderId,exCommand);
            }else{
                //风控校验
                //rimsProcess(order);

                //调用风控服务校验 add by fanghw 20160122
/*            callRiskControlService.transCall(order.getGopayOrderId(), order.getGopayIntTxnCd(), order.getPayChannel(),
                    order.getMerTxnAmt(), order.getMainRecvCustId());*/

                completeOrder(order);
                return new ModelAndView("redirect:/cloud/00100/express/progress.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t=0&orderId="+orderId);
            }
        }catch (GopayException e){
            status = e.getErrMsg()==null?e.getErrCode():e.getErrMsg();
            throw e;
        }finally {
            try {
                if(exCommand.getExPayWay() == BankPayWay.A ||StringUtils.isNotBlank(exCommand.getExCardId())){
                    logger.info("需要校验密码，执行采集数据入库");
                    logMicrodone(getRequest(),mcryptKey, scene,orderId,status,oprInfo.getUser());
                }
            } catch (Exception e1) {
                logger.error("收银台快捷支付二次支付密码控件记录入库异常",e1);
            }
        }



    }
    
    
    
    @RequestMapping(value = "/00100/express/confirm.shtml")
    public ModelAndView balPay(ExpressPayChannelCommand exCommand) throws GopayException {
        printRequest("expressPayConfirm00100Controller-confirm");
        //充值订单
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);

        CpsGenMainOrder order = getMainOrder(orderId, true);
        // 验证
        validate(exCommand, order);

        //防钓鱼校验
        ModelAndView check = checkAntiPhish(exCommand,"/sec/cloud/00100/express/confirm.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+orderId);
        if(check != null)
            return check;
        return next(order,exCommand);
    }


    private String completeOrder(CpsGenMainOrder order) throws GopayException {
        PayDoneResult r = new PayDoneResult();
        r.setSuccess(true);
        r.setPayWay(PayWay.AcctPay);
        r.setOrderId(order.getGopayOrderId());
        String result = cashierPayCallbackService.finish(r);
        return result;
    }

    private  ModelAndView next(CpsGenMainOrder order,ExpressPayChannelCommand exCommand) throws WebException {
        ModelAndView mav = new ModelAndView("/cloud/00100/content/acct/exPayConfirm");
        BankPayWay payWay = exCommand.getExPayWay();
        mav.addObject("exPayWay",payWay.toString());
        mav.addObject("exCardId",exCommand.getExCardId());
        DecimalFormat df = new DecimalFormat("0.00");
        BigDecimal payAmt = order.getMerTxnAmt();
        
        ExpressPoundageVo epv=null;
        if(payWay == BankPayWay.S){//差额支付
            /*BigDecimal bankPayAmt = getActualPayAmt(exCommand, order);
            BigDecimal acctPayAmt = order.getMerTxnAmt().subtract(bankPayAmt);
            mav.addObject("bankPayAmt", df.format(bankPayAmt));
            mav.addObject("acctPayAmt", df.format(acctPayAmt));
            mav.addObject("exPayChannel",exCommand.getExPayChannel());
            mav.addObject("exPayBankCode",exCommand.getExPayBankCode());*/
        }else if(payWay == BankPayWay.A){
        	
        	
        	//如果为付款方承担佣金，并且佣金不为0，则展示
        	if(OrderFeePayer.PAY_PAYER.value.equals(order.getMerCommPayer())
        			&&BigDecimal.ZERO.compareTo(order.getMerCommAmt())<0){
        		epv = getPoundageRes(order,exCommand);
                PoundageRes p = epv.getPoundageRes();
        		
        		mav.addObject("acctPayAmt", df.format(p.getTotalAmt().add(order.getMerCommAmt())));
        	}else{
        		mav.addObject("acctPayAmt", df.format(payAmt));
        	}
        }else if(payWay == BankPayWay.F){
            /*BigDecimal bankPayAmt = getActualPayAmt(exCommand, order);
            mav.addObject("bankPayAmt", df.format(bankPayAmt));
            mav.addObject("exPayChannel",exCommand.getExPayChannel());
            mav.addObject("exPayBankCode",exCommand.getExPayBankCode());*/
        }

        CustPersonInfo personInfo = custPersonInfoQueryManager.get(getLoginUser().getUser().getCustId());
        if(personInfo!=null){
        	mav.addObject("isRealNameCertify",personInfo.getIsRealNameCertify());
        	//未绑定卡即第一次支付时，显示注册时手机号  add by congliang
            if("".equals(exCommand.getExMobileNo())||null==exCommand.getExMobileNo()){
                   exCommand.setExMobileNo(personInfo.getCustMob());
               }
        }
        
        if(payWay != BankPayWay.A){
            if (UserType.Person == UserType.get(getLoginUser().getUser().getUserType())) {
                if(!StringUtils.equals(personInfo.getIsRealNameCertify(),CustPersonInfoConstants.REAL_NAME_CERTIFY_NO)){
                    exCommand.setExHolder(personInfo.getCustName());
                    exCommand.setExIdCardNo(personInfo.getCertNo());
                }
            }
        }


        LoginUser loginUser = getLoginUser();
        if(loginUser!=null){
        	  // 增加校验使用动态口令卡的权限
    		String custId = getLoginUser().getUser().getCustId();
    		boolean flag = userDcPwdManager.getDCAuth(custId);
    		if (flag) {
    			mav.addObject("haveDcAuth", "1");// 1表示有吧
    		}
    		// end
        }
        
        mav.addObject("dcErrMesg", exCommand.getDcErrMsg());

        //加上获取信用卡快捷支付的通道,二次支付并且是信用卡才去调
        String payChannel=exCommand.getExPayChannel();
        String isQueryCVN="";
        /**
         * 从bis中获取
         */
        logger.info("付款渠道:"+payChannel);
        mav.addObject("isYiBao","no");
        if("06".equals(payChannel)){
        Result result = null;
        try {
			ExPayBaseMessage message = getExPayBaseMessage(order,exCommand);
			result=exAuthRemoteService.queryCvn(message);
			logger.info("返回的信息:"+result.isSuccess()+"ddd"+result.getModel("isQueryCVN")+result.getModel("flag"));
		} catch (GopayException e) {
		    logger.info("调用查询CVN2码出错");
			e.printStackTrace();
		}
        Boolean  flag=(Boolean) result.getModel("flag");
          if(result.isSuccess()&&flag){
        	  isQueryCVN=(String) result.getModel("isQueryCVN");
        	  //1表示需要，2表示不需要
	        if("2".equals(isQueryCVN)){
	        	logger.info("最终进来了");
	        	//获取的通道是易宝支付
	        	mav.addObject("isYiBao","yes");
	        	
	        }
          }else{
        	  logger.error("返回的错误信息是:"+result.getModel("retMsg"));
          } 
        }

        mav.addObject("payAmt", df.format(payAmt));
        mav.addObject("order", getOrderInfo(order.getGopayOrderId(),epv));
        mav.addObject("orderId", order.getGopayOrderId());
        mav.addObject("exGopayAcctId", exCommand.getExGopayAcctId());
        mav.addObject("formhash", setReqAttr(KEY_FORM_HASH, getRandom(32)));// 防止hack
        mav.addObject("bankCardNo",exCommand.getBankCardNo());
        mav.addObject("hideBankCardNo",getHiddenCardNo(exCommand.getBankCardNo()));
        mav.addObject("hideMobileNo",getHiddenMobileNo(exCommand.getExMobileNo()));
        //mav.addObject("hideExIdCardNo", getHiddenExIdCardNo(exCommand.getExIdCardNo()));
        mav.addObject("temp",exCommand);
        //mav.addObject("portal_url",PORTAL_URL);
        mav.addObject("cloudat_url",CLOUD_URL);
        mav.addObject("cas_server_url",CAS_URL);
        return mav;
    }

    private  ModelAndView bankPay(String orgOrderId,ExpressPayChannelCommand exCommand) throws GopayException {
        PayResult result = null;
        EpCardBindInfo info = bindCardInfo(exCommand);
        if (StringUtils.isNotBlank(exCommand.getExCardId())) {
            // 二次支付,调用鉴权接口
            CpsGenMainOrder order = getMainOrder(orgOrderId, true);
            Result cerResult = exAuthRemoteService.certification(getExPayBaseMessage(order,
                    getExCommand(exCommand, info)));
            if(cerResult != null){
                logger.error("express bank certification orderId:"+orgOrderId+" inChargeOrderId:"+exCommand.getInChargeOrderId()+" res:"+cerResult.isSuccess()+" resCode:"+cerResult.getResultCode());
            }
        }
        //新额度校验前置更新银行卡号
        updatePayOrder(exCommand.getInChargeOrderId(), exCommand.getBankCardNo());

        result = exPayRemoteService.pay(getPayRequest(exCommand.getInChargeOrderId(),getExCommand(exCommand,info)));
        if(result != null){
            logger.info("express bank pay orderId:"+orgOrderId+" inChargeOrderId:"+exCommand.getInChargeOrderId()+" res:"+result.isSuccess()+" resCode:"+result.getResultCode());
        }
        return  new ModelAndView("redirect:/00100/express/progress.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t="+(info != null ?info.getSq() : 0)+"&orderId="+orgOrderId+"&inOrderId="+exCommand.getInChargeOrderId());
    }

    private String saveInchargeOrder(ExpressPayChannelCommand command,CpsGenMainOrder order) throws WebException {
        String inchargeOrderId = "";
        PayChannel payChannel = PayChannel.get(command.getExPayChannel());
        // 计算银行卡实际支付金额，如果是全额支付，则为订单金额；如果是差额支付，则为订单金额减去账户可用余额
        BigDecimal actualPayAmt = getActualPayAmt(command, order);
        LoginUser user = getLoginUser();
        String custId = (null == user || null == user.getUser()) ? "-" : user.getUser().getCustId();
        try {
            logger.error("saving incharge order." + command);
            inchargeOrderId = cashierPayCallbackService.saveInchargeOrder(order.getGopayOrderId(),actualPayAmt.toString(), payChannel.value, command.getExPayBankCode(), custId);
            logger.error("saving incharge order." + inchargeOrderId + ", " + command);
        } catch (GopayException e) {
            logger.error("shortfallpay saveInchargeOrder error!" + command, e);
            throw new WebException(e.getErrCode());
        }
        return inchargeOrderId;
    }
    private void updateOrder(ExpressPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        LoginUser loginUser = getLoginUser();
        //计算手续费
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PayChannel payChannel = epv.getPayChannel();
        PoundageRes p = epv.getPoundageRes();

        if(loginUser!=null){
            values.put(MainOrderField.PAY_CUST_ID, loginUser.getUser().getCustId());
            values.put(MainOrderField.PAY_ACCT, command.getExGopayAcctId());
        }
        values.put(MainOrderField.PAY_CHANNEL, payChannel.toString());
        values.put(MainOrderField.OUT_STLM_ID, command.getExPayBankCode());
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());

        /**远程IP地址 songefengli 20160922**/
        values.put(MainOrderField.REMOTE_IP, RequestUtils.getRemoteRealIpAddr(getRequest()));

        //云账户 计算总金额  总金额=交易金额+手续费+佣金
        if(IntTxnCd._00100.value.equals(order.getGopayIntTxnCd())
				&&GatewaySource.GATEWAY_SOURCE_06.value.equals(order.getGatewaySource())
				&&order.getMerCommAmt().compareTo(BigDecimal.ZERO)>0
        		){
        	values.put(MainOrderField.TOTAL_ORDER_AMT, (p.getTotalAmt().add(order.getMerCommAmt())).toString());
        }else{
        	values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        }
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.ORDER_FEE_PAYER, p.getOrderFeePayer().value);
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 start**/
        values.put(MainOrderField.SETTLE_AMT, p.getSettleAmt().toPlainString());
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 end**/
        
        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }
        }

        try {
            logger.error("调用cps更新订单状态.BEGIN.call cps update mainOrder." + command + ", " + order + ", " + values);
            mainOrderUpdateService.payUpdate(order.getGopayOrderId(), values);
            logger.error("调用cps更新订单状态.END.call cps update mainOrder." + command + ", " + order);
        } catch (GopayException e) {
            logger.error("调用cps更新订单状态出错！call cps update mainOrder exception!" + command + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
        //下面的校验都是根据不同的手续费承担方  网关支付需要进行的余额校验
        if(command.getExPayWay() == BankPayWay.F){
        	   
            //手续费选择收款方付手续费，网关支付选择企业网银付款：此时应该有收款方可用余额大于等于手续费金额
      		if(StringUtils.equals(OrderFeePayer.REC_PAYER.value, order.getOrderFeePayer())){
      			AcctMastBean revAcct=acctTransService.getAccount(order.getMainRecvAcct());
      			if(new BigDecimal(revAcct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9107);
      			}
      		}
      		//手续费选择商城付手续费，网关支付选择企业网银付款：此时应该有商城可用余额大于等于手续费金额
      		if(StringUtils.equals(OrderFeePayer.MER_PAYER.value, order.getOrderFeePayer())){
      			AcctMastBean merAcct=acctTransService.getAccount(order.getRemark1());
      			if(new BigDecimal(merAcct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9107);
      			}
      		}
        	
        }
        else if(command.getExPayWay() == BankPayWay.A){
        	//手续费选择付款方付手续费，网关支付选择企业虚拟账户付款：此时应该有子账户可用余额大于等于（交易金额+手续费金额+佣金金额）的校验
        	if(StringUtils.equals(OrderFeePayer.PAY_PAYER.value, order.getOrderFeePayer())){
      			AcctMastBean payAcct=acctTransService.getAccount(order.getPayAcct());
      			BigDecimal total=p.getTotalAmt();
      			
      			if(BigDecimal.ZERO.compareTo(order.getMerCommAmt())<0){
      				total=total.add(order.getMerCommAmt());
      			}
      			if(BigDecimal.ZERO.compareTo(p.getTotalFeeAmt())<0){
      				total=total.add(p.getTotalFeeAmt());
      			}
      			if(new BigDecimal(payAcct.getAvaAmt()).compareTo(total)<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9108);
      			}
      		}
        	
        	//手续费选择收款方付手续费，网关支付选择企业虚拟账户付款：此时应该有付款方可用余额大于等于（交易金额+佣金）；
        	//收款方可用余额大于等于手续费金额
      		if(StringUtils.equals(OrderFeePayer.REC_PAYER.value, order.getOrderFeePayer())){
      			AcctMastBean payAcct=acctTransService.getAccount(order.getPayAcct());
      			BigDecimal total=p.getOrderDealAmt();
      			
      			if(BigDecimal.ZERO.compareTo(order.getMerCommAmt())<0){
      				total=total.add(order.getMerCommAmt());
      			}
      			if(new BigDecimal(payAcct.getAvaAmt()).compareTo(total)<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9110);
      			}
      			
      			AcctMastBean revAcct=acctTransService.getAccount(order.getMainRecvAcct());
      			if(new BigDecimal(revAcct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9107);
      			}
      			
      		}
        	//手续费选择商城付手续费，网关支付选择企业虚拟账户付款：此时应该有付款方可用余额大于等于（交易金额+佣金）；
      		//商城可用余额大于等于手续费金额
      		if(StringUtils.equals(OrderFeePayer.MER_PAYER.value, order.getOrderFeePayer())){
      			AcctMastBean payAcct=acctTransService.getAccount(order.getPayAcct());
      			BigDecimal total=p.getOrderDealAmt();
      			
      			if(BigDecimal.ZERO.compareTo(order.getMerCommAmt())<0){
      				total=total.add(order.getMerCommAmt());
      			}
      			if(new BigDecimal(payAcct.getAvaAmt()).compareTo(total)<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9110);
      			}
      			
      			AcctMastBean merAcct=acctTransService.getAccount(order.getRemark1());
      			if(new BigDecimal(merAcct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
      				throw new WebException(ProcCodeConstants.PROC_CODE_100E9107);
      			}
      			
      		}
        	
        	
        }
    }
    /*
    private void updateOrder(ExpressPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        LoginUser loginUser = getLoginUser();
        //计算手续费
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PayChannel payChannel = epv.getPayChannel();
        PoundageRes p = epv.getPoundageRes();

        if(loginUser!=null){
            values.put(MainOrderField.PAY_CUST_ID, loginUser.getUser().getCustId());
            values.put(MainOrderField.PAY_ACCT, command.getExGopayAcctId());
        }
        values.put(MainOrderField.PAY_CHANNEL, payChannel.value);
        values.put(MainOrderField.OUT_STLM_ID, command.getExPayBankCode());
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.ORDER_FEE_PAYER, p.getOrderFeePayer().value);
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        
        
        
        

        
        
        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }
        }

        try {
            logger.error("调用cps更新订单状态.BEGIN.call cps update mainOrder." + command + ", " + order + ", " + values);
            mainOrderUpdateService.payUpdate(order.getGopayOrderId(), values);
            logger.error("调用cps更新订单状态.END.call cps update mainOrder." + command + ", " + order);
        } catch (GopayException e) {
            logger.error("调用cps更新订单状态出错！call cps update mainOrder exception!" + command + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
    }*/

    private void updateOrderProcess(CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        try {
            order.setTxnStaCd(TxnStaCode.TXN_STA_CD_30101.value);
            mainOrderUpdateService.updateMany(order.getGopayOrderId(), values);
        } catch (GopayException e) {
            throw new WebException(e.getErrCode());
        }
    }


    private boolean validateSubmit(ExpressPayChannelCommand command,String mcryptKey) {
        String payPwd = null;
        String checkPwd = getRequest().getParameter("checkPwd");
        if(StringUtils.isNotBlank(checkPwd) && Boolean.valueOf(checkPwd)){
            if(command.getExPayWay() != BankPayWay.A){
                if(StringUtils.isNotBlank(command.getExCardId())){
                    EpCardBindInfo info = epBankCardService.getCardInfoById(command.getExCardId());
                    PayChannel cardCh = EpCardType.CREDIT == info.getBankAcctType() ? PayChannel._06 : PayChannel._03;
                    if(cardCh == PayChannel._03 && StringUtils.isNotBlank(command.getExIdCardNo6())){
                        String idCard = info.getCertNo().substring(info.getCertNo().length()-6,info.getCertNo().length());
                        if(!StringUtils.equals(command.getExIdCardNo6(),idCard)){
                            EpCardStatus cardStatus = epBankCardService.errAccum4CertNo(info.getBankAcctNum());
                            String err = "您当日的错误次数超限，该卡已被冻结";
                            if(cardStatus.getStatus() != EpCardStatus.STATUS_FREEZE){
                                err = "身份证号后六位错误，您还有"+(EpCardStatus.CERT_NO_ERR_MAX - cardStatus.getCertNoErrNum())+"次机会";
                            }
                            command.setErrMsg(err);
                            command.setErrId("2");
                            return false;
                        }
                    }
                }
            }

            try {
//                payPwd = PwdControlUtil.decryptPwd(getRequest(), command.getPayPassword());
                payPwd = AESWithJCE.getResult(mcryptKey, command.getPayPassword());//调用解密接口.获得密码明文。
            } catch (Exception e) {
                logger.error("密码解密发生错误！！ Error occurs while decrypting password!!" + command, e);
                command.setErrId("1");
                command.setErrMsg("密码解密发生错误");
                return false;
            }
            UserPayPwdResult res = userPayPwdManager.verifyPayPwd(getLoginUser().getUser().getUserId(), payPwd);
            if(res == null || !res.isVerifySuccess()){
                command.setErrMsg(res==null ? "支付密码校验失败":res.getErrorMsg());
                command.setErrId("1");
                return false;
            }
        }

		// 校验动态口令卡
		if (getLoginUser() != null) {
			String custId = getLoginUser().getUser().getCustId();
			//将原有的根据custId查询动态口令信息修改称为根据userID查询动态口令
			String userId = getLoginUser().getUser().getUserId();
			boolean flag = userDcPwdManager.getDCAuth(custId);
			boolean flag1 = userDcPwdManager.getDCAuthbyUserId(userId);
			if (flag) {// 有使用的才校验
				String dcPass = getRequest().getParameter("dcpass");
				String dcErrMesg = "";
				try {
					dcErrMesg = userDcPwdManager.getErrMesg(custId, dcPass);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					command.setDcErrMsg("校验动态口令卡出错了");
					return false;
				}

				if (!"".equals(dcErrMesg)) {
					command.setDcErrMsg(dcErrMesg);
					return false;
				}

			}
			
			if (flag1) {// 有使用的才校验
                String dcPass = getRequest().getParameter("dcpass");
                String dcErrMesg = "";
                try {
                    dcErrMesg = userDcPwdManager.getErrMesgByUserId(userId, dcPass);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    command.setDcErrMsg("校验动态口令卡出错了");
                    return false;
                }

                if (!"".equals(dcErrMesg)) {
                    command.setDcErrMsg(dcErrMesg);
                    return false;
                }

            }
		}
        
        
        return  true;
    }


    private void validate(ExpressPayChannelCommand command, CpsGenMainOrder order) throws GopayException {
        HttpServletRequest request = getRequest();
        LoginUser loginUser = getLoginUser();
        if(loginUser == null){
            logger.error(this.getClass() + " loginUser is null " + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100W1006);
        }
        if(command.getExPayWay() != BankPayWay.A){
            if(StringUtils.isNotBlank(command.getExCardId())){
                EpCardBindInfo info = epBankCardService.getCardInfoById(command.getExCardId());
                if(info == null){
                    logger.error(this.getClass() + " EpCardBindInfo is null " + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
                PayChannel cardCh = EpCardType.CREDIT == info.getBankAcctType() ? PayChannel._06 : PayChannel._03;
                if(!StringUtils.equals(command.getExPayBankCode(),info.getBankCode()) || !StringUtils.equals(command.getExPayChannel(),cardCh.value)){
                    logger.error(this.getClass() + " pay bank code  is not match " + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
                command.setExMobileNo(info.getBindMobile());
                command.setBankCardNo(info.getBankAcctNum());

                boolean freeze = epBankCardService.isFreezeCardNo(info.getBankAcctNum());
                if(freeze){
                    logger.error(this.getClass() + info.getBankAcctNum()+" was freezed " + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E5118);
                }
            }else{
                command.setExCardId("");
                if (StringUtils.isBlank(command.getExPayBankCode())) {
                    logger.error(this.getClass() + "没有选择银行！ no bank selected!!" + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
                if (StringUtils.isBlank(command.getExPayChannel())) {
                    logger.error(this.getClass() + "没有选择银行类型！ no paychannel selected!!" + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
            }
        }

        if (null == order) {
            logger.error("找不到订单！order not exits!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (TxnStaCode.TXN_STA_CD_30000.value != (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }
        if(StringUtils.equals(loginUser.getUser().getCustId(), order.getMainRecvCustId()) || (StringUtils.isNotBlank(command.getExGopayAcctId()) && StringUtils.equals(command.getExGopayAcctId(), order.getMainRecvAcct()))){
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5011);
        }
        UserInfo userInfo = loginUser.getUser();
        if (null == userInfo || UserInfoConstants.USER_STAT_CANCEL.equals(userInfo.getUserStat())) {
            logger.error("用户不存在或尚未登录！user not exist or not login! " + request.getRemoteUser());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2001);
        }
        if (!UserInfoConstants.USER_STAT_NORMAL.equals(userInfo.getUserStat())) {
            logger.error("用户状态异常：" + userInfo.getCustId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2002);
        }
        String userType = userInfo.getUserType();
        if (UserInfoConstants.USER_TYPE_PERSON.equals(userType)) {
            CustPersonInfo info = custPersonInfoQueryManager.get(userInfo.getCustId());
            if (info == null || CustPersonInfoConstants.CUST_STAT_CANCEL.equals(info.getCustStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
            }
            if (!CustPersonInfoConstants.CUST_STAT_NORMAL.equals(info.getCustStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
            }
        } else if (userType.startsWith("2")) {
            CustCorpInfo info = custCorpInfoService.get(userInfo.getCustId());
            if (info == null || CustCorpInfoConstants.CORP_STAT_CANCEL.toString().equals(info.getCorpStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
            }
            if (!CustCorpInfoConstants.CORP_STAT_NORMAL.toString().equals(info.getCorpStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
            }
        } else {
            throw new WebException(ProcCodeConstants.PROC_CODE_100E1027);
        }

        //校验收款方
        checkRecvCustStatus(0, order.getMainRecvCustId());
        AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
        if (null == acct) {
            logger.error("账户不存在,acctId=" + order.getMainRecvAcct());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
        }
        if (AcctStatus.F.equals(acct.getAccStatus())) {
            if (FrezCode.CRE.equals(acct.getFrezCode()) || FrezCode.FUL.equals(acct.getFrezCode())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E3025, "账户[" + order.getMainRecvAcct()
                        + "]处于冻结状态[" + acct.getFrezCode() + "]，无法入款");
            }
        }
    }

    /**
     * 计算正确的差额支付金额，同时进行校验
     */
    private BigDecimal getActualPayAmt(ExpressPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        if (command.getExPayWay() == BankPayWay.S) {
            BigDecimal orderAmt = order.getMerTxnAmt();
            AcctMastBean acct = acctTransService.getAccount(command.getExGopayAcctId());
            if (null == acct) {
                logger.error("账户不存在！acctMast not exist!" + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_000E3001);
            }
            BigDecimal acctBalance = new BigDecimal(acct.getAvaAmt());
            //账户可用余额 + 差额支付金额 = 订单金额
            if(orderAmt.compareTo(acctBalance)==1){
                BigDecimal shortfallPayAmt = orderAmt.subtract(acctBalance);
                return shortfallPayAmt;
            }
        }
        return order.getMerTxnAmt();
    }

    private ExPayBaseMessage getExPayBaseMessage(CpsGenMainOrder order,ExpressPayChannelCommand command) throws GopayException{
        ExPayBaseMessage base = new ExPayBaseMessage();
        base.setBank(command.getExPayBankCode());
        base.setOrderId(order.getGopayOrderId());
        base.setAmount(order.getMerTxnAmt());
        base.setBankBusProd(BisBankBusinessProd._15);
        base.setMediaId(command.getExMobileNo());
        base.setCardNo(command.getBankCardNo());
        base.setCardHolder(command.getExHolder());
        base.setIdentityCode(command.getExIdCardNo());
        base.setIdentityType(CustPersonInfoConstants.CERT_TYPE_IDCARD);
        if(StringUtils.equals(order.getPayChannel(),PayChannel._06.toString()) || StringUtils.equals(command.getExPayChannel(),PayChannel._06.toString())){
            base.setCvv2(command.getExCvn2());
            base.setAvailableDate(command.getExValidDate());
            base.setBankOrderType(BisBankBusinessProdConvertUtil.getBisBankBusinessProd(PayChannel.get(command.getExPayChannel())).value);
            base.setBankBusProd(BisBankBusinessProd._05);
        }
        base.setBrowser(ExPayBankConstants.VAL_BROWSER_VERSION_NUMBER);
        base.setUserIp(RequestUtils.getRemoteRealIpAddr(getRequest()));
        base.setTermination(ExPayBankConstants.TERMINAL_TYPE_PC);
        return  base;
    }
    
    protected OrderInfo getOrderInfo(String gopayOrderId,ExpressPoundageVo epv) throws WebException {
        OrderInfo orderInfo = new OrderInfo();
        CpsGenMainOrder order = cpsGeneralMainOrderQueryDAO.find(CpsGenMainOrder.class, gopayOrderId);
        CustCorpInfo cust = (null == order) ? null : custCorpInfoService.get(order.getMainRecvCustId());
        //CustCorpInfo cust = (null == order) ? null : custCorpInfoService.get(order.getMerId());
        if (null == order) {
            logger.error("订单不存在！order not exist!" + gopayOrderId);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (null == cust) {
            logger.error("商户不存在！cust not exist!" + gopayOrderId);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
        }
        orderInfo.setMerOrderId(order.getMerOrderId());
        DecimalFormat f = new DecimalFormat("0.00");
        // 默认取订单总金额，但是订单刚提交到收银台时，此值为0（还没有计算手续费），因此收银台首页需要显示MerTxnAmt（单独处理:在调用getOrderInfo()方法后再setOrderAmt）。
        orderInfo.setOrderAmt(f.format(order.getTotalOrderAmt()));
        if(epv!=null){
        	PoundageRes p = epv.getPoundageRes();
            orderInfo.setFeeAmt(f.format(p.getTotalFeeAmt()));
        }else{
        	
        	orderInfo.setFeeAmt(f.format(order.getTotalOrderFeeAmt()));
        }
        orderInfo.setOrderDate(DateUtils.date2string(order.getMerTxnTm(), "yyyy-MM-dd HH:mm:ss"));
        orderInfo.setOrderId(gopayOrderId);
        orderInfo.setIntTxnCd(order.getGopayIntTxnCd());
        orderInfo.setFeePayer(order.getOrderFeePayer());
        if(order.getMerCommAmt() != null && StringUtils.equals(MerCommPayer._PAY.value,order.getMerCommPayer()))
            orderInfo.setMerCommAmt(f.format(order.getMerCommAmt()));//平台佣金
        String merName;
        // 如果是充值交易，要显示充值用户的用户名称
        if (isInchargeOrder(order) || isP2P(order)) {
            CustCorpInfo corp = custCorpInfoService.get(order.getMainRecvCustId());
            if (null == corp) {// 个人用户
                CustPersonInfo person = custPersonInfoQueryManager.get(order.getMainRecvCustId());
                if (null == person) {
                    logger.error("个人用户不存在！person not exist!" + gopayOrderId);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
                }
                if(StringUtils.equals(person.getRegType(),CustPersonInfoConstants.REG_TYPE_MOBILE)){
                    merName = person.getCustMob();
                }else{
                    merName = person.getEmail();
                }
            } else {
                if(StringUtils.equals(corp.getRegType(),CustCorpInfoConstants.REG_TYPE_MOBILE)){
                    merName = corp.getCustMob();
                }else{
                    merName = corp.getEmail();
                }
            }
        } else {
        	merName = cust.getCorpName();
            //merName = cust.getMerName();
        }
        logger.error(merName+"####"+cust+"orderId="+order.getMerOrderId());
        orderInfo.setRecvName(merName);
        orderInfo.setMerTxnAmt(f.format(order.getMerTxnAmt()));
        return orderInfo;
    }
}
